#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdint.h>
#include <stdbool.h>
#include <curl/curl.h>

#define FALSE   false
#define TRUE    true
#define TEST_ERR_MAJOR_BAD     100
#define test_setopt(A,B,C) \
    if((res = curl_easy_setopt((A),(B),(C))) != CURLE_OK) goto test_cleanup

static int task_progress_cb(void *clientp,
         double dltotal,
          double dlnow,
          double ultotal,
            double ulnow)
{
    printf("%ld\t/\t%ld\r", (long int)ulnow, (long int)ultotal);

    return 0;
}

/*
 * Get a single URL without select().
 */

int test(char *URL, const char * localfile, int upload)
{
    CURL *c;
    CURLM *m = NULL;
    int res = 0;
    int running=1;
    long res_code;

    if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
        fprintf(stderr, "curl_global_init() failed\n");
        return TEST_ERR_MAJOR_BAD;
    }

    if ((c = curl_easy_init()) == NULL) {
        fprintf(stderr, "curl_easy_init() failed\n");
        curl_global_cleanup();
        return TEST_ERR_MAJOR_BAD;
    }


    FILE *protofile = NULL;
    if (upload) {
        protofile = fopen(localfile, "rb");
        test_setopt(c, CURLOPT_UPLOAD, 1);
        test_setopt(c, CURLOPT_READDATA, protofile);
    }
    else {
        protofile = fopen(localfile, "wb");
        test_setopt(c, CURLOPT_WRITEDATA, protofile);
    }

    if(protofile == NULL) {
        fprintf(stderr, "Couldn't open the protocol dump file\n");
        return TEST_ERR_MAJOR_BAD;
    }

    test_setopt(c, CURLOPT_NOPROGRESS, 0L);
    test_setopt(c, CURLOPT_PROGRESSFUNCTION, task_progress_cb);
    test_setopt(c, CURLOPT_URL, URL);
    test_setopt(c, CURLOPT_MAX_RECV_SPEED_LARGE, (curl_off_t)3000*4096);
    test_setopt(c, CURLOPT_MAX_SEND_SPEED_LARGE, (curl_off_t)1024);


    if ((m = curl_multi_init()) == NULL) {
        fprintf(stderr, "curl_multi_init() failed\n");
        curl_easy_cleanup(c);
        curl_global_cleanup();
        return TEST_ERR_MAJOR_BAD;
    }

    if ((res = (int)curl_multi_add_handle(m, c)) != CURLM_OK) {
        fprintf(stderr, "curl_multi_add_handle() failed, "
                "with code %d\n", res);
        curl_multi_cleanup(m);
        curl_easy_cleanup(c);
        curl_global_cleanup();
        return TEST_ERR_MAJOR_BAD;
    }
    while (running) { 
        res = (int)curl_multi_perform(m, &running);
        if (running <= 0) {
            fprintf(stderr, "nothing left running.\n");
            break;
        }
    }

    curl_easy_getinfo(c, CURLINFO_RESPONSE_CODE, &res_code);
    fprintf(stderr, "task result:%ld\n", res_code);

test_cleanup:

    if (protofile){
        fclose(protofile);
    }

    if(m) {
        curl_multi_remove_handle(m, c);
        curl_multi_cleanup(m);
    }
    curl_easy_cleanup(c);
    curl_global_cleanup();

    return res;
}

int main (int argc, char * argv[])
{
    return test(argv[1], argv[2], (argv[3]!=NULL));
}

